﻿#pragma once

#include <algorithm>
#include <memory>
#include <set>
#include <unordered_set>
#include <vector>

#include <learn/check.h>
#include <learn/topo/property_handle.h>

namespace xi
{

namespace topo
{

// 前向声明
class EXT_SYMBOL Topo_Vertex;
class EXT_SYMBOL Topo_Edge;
class EXT_SYMBOL Topo_Coedge;
class EXT_SYMBOL Topo_Face;
class EXT_SYMBOL Topo_Wire;
class EXT_SYMBOL Topo_Shell;
class EXT_SYMBOL Topo_Explorer;
class EXT_SYMBOL Topo_Builder;

// 句柄类型
using VHandle = Topo_Vertex *;
using EHandle = Topo_Edge *;
using CHandle = Topo_Coedge *;
using FHandle = Topo_Face *;
using WHandle = Topo_Wire *;
using SHandle = Topo_Shell *;

// 特例化为针对不同类型的属性
template <typename T> using VProperty_Handle = Property_Handle<T, Topo_Vertex>;
template <typename T> using EProperty_Handle = Property_Handle<T, Topo_Edge>;
template <typename T> using CProperty_Handle = Property_Handle<T, Topo_Coedge>;
template <typename T> using FProperty_Handle = Property_Handle<T, Topo_Face>;
template <typename T> using WProperty_Handle = Property_Handle<T, Topo_Wire>;
template <typename T> using SProperty_Handle = Property_Handle<T, Topo_Shell>;

// 拓扑方向
enum class EXT_SYMBOL Topo_Dir
{
    Forward,  // 与底层几何同向
    Backward, // 与底层几何反向
};

// 循环类型
enum class EXT_SYMBOL Topo_Loop
{
    Boundary, // 边界环
    Interior, // 内部环
};

// 拓扑类型
enum class EXT_SYMBOL Topo_Type
{
    Vertex,
    Edge,
    Coedge,
    Face,
    Wire,
    Shell,
};

struct EXT_SYMBOL Topo_Prop
{
  public:
    std::vector<Property_Base *> prop;

    /**
     * @brief 释放所有属性
     *
     */
    ~Topo_Prop();
};

class EXT_SYMBOL Topo_Shape
{
  public:
    /**
     * @brief 基本构造
     *
     */
    Topo_Shape();

    /**
     * @brief 删除所有赋值和拷贝构造函数
     *
     */
    Topo_Shape(Topo_Shape &&) = delete;

    /**
     * @brief 析构函数
     *
     */
    virtual ~Topo_Shape() = default;

    /**
     * @brief 是否具有属性
     *
     * @param[in] prop
     * @return true
     * @return false
     */
    bool has_property(const Property_Base &prop) const
    {
        if (m_properties == nullptr)
            return false;

        auto it = std::find_if(m_properties->prop.begin(), m_properties->prop.end(),
                               [&](Property_Base *val) { return val->name() == prop.name(); });
        return it != m_properties->prop.end();
    }

    /**
     * @brief 移除属性
     *
     * @param[in] prop
     */
    void remove_property(const Property_Base &prop)
    {
        auto it = std::find_if(m_properties->prop.begin(), m_properties->prop.end(),
                               [&](Property_Base *val) { return val->name() == prop.name(); });
        delete *it;
        m_properties->prop.erase(it);

        if (m_properties->prop.empty())
            m_properties.reset();
    }

  protected:
    std::unique_ptr<Topo_Prop> m_properties;
};

} // namespace topo

} // namespace xi
